package com.unionftech.common.base.mvp.impl

import com.unionftech.common.bean.ApiException
import com.unionftech.common.bean.ResponseResult
import com.unionftech.common.utils.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

abstract class BaseModel {
    private var mainScope: CoroutineScope = MainScope()

    companion object {
        private const val TAG = "BaseModel"
    }

    /**
     * 处理模块统一接口的业务逻辑，
     * 如果返回false则不会拦截网络接口返回值，
     * 返回true需要重写getBusinessErrorMsg方法返回业务处理结果，不会返回网络接口结果
     */
    open fun handleBusinessError(res: ResponseResult<*>): Boolean {
        return false
    }

    /**
     * 返回模块统一业务处理的错误提示信息
     */
    open fun getBusinessErrorMsg(res: ResponseResult<*>): String {
        return "self handle business error"
    }

    fun execute(call: suspend CoroutineScope.() -> Unit) = mainScope.launch {
        try {
            call()
        } catch (e: Throwable) {
            LogUtils.e(TAG, "execute error msg:${e.message}")
            e.printStackTrace()
            //此处接收到BaseModel里的request抛出的异常
            //根据业务逻辑自行处理代码..
        }
    }

    suspend fun <T> request(call: suspend () -> ResponseResult<T>): ResponseResult<T> {
        return withContext(Dispatchers.IO) {
            val res: ResponseResult<T>
            try {
                res = call.invoke()
            } catch (e: Throwable) {
                LogUtils.e(TAG, "request error msg:${e.message}")
                e.printStackTrace()
                // 请求出错，将状态码和消息封装为 ResponseResult
                return@withContext ApiException.build(e).toResponse<T>()
            }

            //这里可以处理所有接口请求统一的业务逻辑处理
            if (handleBusinessError(res)) {
                return@withContext ApiException.build(
                    ApiException.CODE_SELF_HANDLE_ERROR,
                    getBusinessErrorMsg(res)
                ).toResponse<T>()
            }
            return@withContext res
        }
    }

    fun detach() {
        mainScope.cancel()
    }
}